// ///////////////////////////// MIT License //////////////////////////////////// //
//                                                                                //
// Copyright (c) 2010 David Zsolt Manrique                                        //
//                    david.zsolt.manrique@gmail.com                              //
//                                                                                //
// Permission is hereby granted, free of charge, to any person obtaining a copy   //
// of this software and associated documentation files (the "Software"), to deal  //
// in the Software without restriction, including without limitation the rights   //
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell      //
// copies of the Software, and to permit persons to whom the Software is          //
// furnished to do so, subject to the following conditions:                       //
//                                                                                //
// The above copyright notice and this permission notice shall be included in     //
// all copies or substantial portions of the Software.                            //
//                                                                                //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR     //
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,       //
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE    //
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER         //
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,  //
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN      //
// THE SOFTWARE.                                                                  //
//                                                                                //
// ////////////////////////////////////////////////////////////////////////////// //

#ifndef CMDIOUTIL_H
#define CMDIOUTIL_H

// standard headers
#include <iostream>
#include <sstream>
#include <fstream>
#include <string>
#include <vector>
#include <list>
#include <set>
#include <map>
#include <iomanip>
#include <cmath>
#include <cstdarg>
#include <stdexcept>
#include <utility>
#include <tuple>

namespace util
{


//! Sort and swap. As result: a < b
template<typename T>
inline void sort(T &a,T &b) { if(b < a) std::swap(a,b); }
                
//! Sort and swap three variables. As result: a < b < c
template<typename T>
inline void sort(T &a,T &b,T &c)
{ if(b < a) std::swap(a,b); if(c < a) std::swap(a,c); if(c < b) std::swap(b,c); }
                                                        
                                                        

template<typename Fr,typename To>
bool to(const Fr & fr,To & to)
{
        std::stringstream ss; 
        ss<<fr;
        return ss>>to;
}

                                        
template<typename T1,typename T2,char d=','>
struct tuple_ex2 :  std::tuple<T1,T2>
{
    tuple_ex2() {}
    tuple_ex2(std::string e)   { get(e); }

    bool get(std::string e)
    {
        if(e.find_first_of(d) == std::string::npos) return false;
        return to(e.substr(0,e.find_first_of(d)),std::get<0>(*this) ) &&
               to(e.substr(e.find_first_of(d)+1),std::get<1>(*this));
    }
};

template<typename T1,typename T2,char d>
std::istream & operator >> (std::istream & is,tuple_ex2<T1,T2,d> & x)
{
        std::string e; is >> e; if (!x.get(e)) is.setstate(std::ios_base::failbit);
        return is;
}

template<typename T1,typename T2,typename T3,char d1=',',char d2=d1>
struct tuple_ex3 : std::tuple<T1,T2,T3>
{
    tuple_ex3() {}
    tuple_ex3(std::string e) { get(e); }
    bool get(std::string e)
    {
        size_t pos1 = e.find_first_of(d1);
        size_t pos2 = e.find_first_of(d2,pos1+1);        
        if( (pos1 == std::string::npos) || (pos2 == std::string::npos) ) return false;
        return to(e.substr(0,pos1),std::get<0>(*this) ) && 
               to(e.substr(pos1+1,pos2-pos1-1),std::get<1>(*this)) &&
               to(e.substr(pos2+1),std::get<2>(*this));
    }
};
template<typename T1,typename T2,typename T3,char d1,char d2>
std::istream & operator >> (std::istream & is,tuple_ex3<T1,T2,T3,d1,d2> & x)
{
        std::string e; is >> e; if (!x.get(e)) is.setstate(std::ios_base::failbit);
        return is;
}

template<typename T1,typename T2,typename T3,typename T4,char d1=',',char d2=d1,char d3=d2>
struct tuple_ex4 : std::tuple<T1,T2,T3,T4>
{
    tuple_ex4() {}
    tuple_ex4(std::string e) { get(e); }
    bool get(std::string e)
    {
        size_t pos1 = e.find_first_of(d1);
        size_t pos2 = e.find_first_of(d2,pos1+1);        
        size_t pos3 = e.find_first_of(d3,pos2+1);        
        if( (pos1 == std::string::npos) || (pos2 == std::string::npos) || (pos3 == std::string::npos) ) return false;
        return to(e.substr(0,pos1),std::get<0>(*this) ) && 
               to(e.substr(pos1+1,pos2-pos1-1),std::get<1>(*this)) &&
               to(e.substr(pos2+1,pos3-pos2-1),std::get<2>(*this)) &&
               to(e.substr(pos3+1),std::get<3>(*this));
    }
};


template<typename T1,typename T2,typename T3,typename T4,char d1,char d2,char d3>
std::istream & operator >> (std::istream & is,tuple_ex4<T1,T2,T3,T4,d1,d2,d3> & x)
{
        std::string e; is >> e; if (!x.get(e)) is.setstate(std::ios_base::failbit);
        return is;
}


template<typename T, char d=',', char r=':'>
struct range_expression : std::list<T>
{
    range_expression() {}
    range_expression(std::string e) { get(e); }
    bool get(std::string e)
    {
        this->clear();
            
        size_t pos = 0;

        do
        {
            size_t pd = e.find_first_of(d,pos);
            std::string s = e.substr(pos,pd-pos);
            size_t pr = s.find_first_of(r);
            if(pr == std::string::npos)
            {
                T i;
                if(to(s,i) == false) return false;
                this->push_back(i);
            }
            else
            {
                T br,er;
                if( to(s.substr(0,pr),br) && to(s.substr(pr+1),er) == false ) return false;
                if(br < er) 
                for(T i = br; i<= er; i++) this->push_back(i);
                else
                for(T i = br; i>= er; i--) this->push_back(i);
            }
            pos = pd + 1;
            
        } while (pos-1 != std::string::npos);
	
	return true;
        
    }
};

template<typename T, char d, char r>
std::istream & operator >> (std::istream & is,range_expression<T,d,r> & x)
{
        std::string e; is >> e; if (!x.get(e)) is.setstate(std::ios_base::failbit);
        return is;
}



template<typename T, char d=','>
struct list_expression : std::list<T>
{
    list_expression() {}
    list_expression(std::string e) { get(e); }
    bool get(std::string e)
    {
        this->clear();
        
        size_t pos = 0;

        do
        {
            size_t pd = e.find_first_of(d,pos);
            std::string s = e.substr(pos,pd-pos);

            T i;
            if(to(s,i) == false) return false;
            this->push_back(i);
            pos = pd + 1;
            
        } while (pos-1 != std::string::npos);
	
	return true;
        
    }
};

template<typename T, char d>
std::istream & operator >> (std::istream & is,list_expression<T,d> & x)
{
        std::string e; is >> e; if (!x.get(e)) is.setstate(std::ios_base::failbit);
        return is;
}


//! marked expression class
//! it can be marked or not marked variable with one prefix character
//! note that the expression cannot contain whitespace
template<typename T,char prefix='*'>
struct prefix_expression : std::tuple<T,bool>
{
	prefix_expression()  {}
        prefix_expression(std::string e) { get(e); }
        bool get(std::string e)
        {
		if(e[0] == prefix) 
		{
                        std::get<1>(*this) = true;
                        return to(e.substr(1),std::get<0>(*this));
		}
                
                return to(e,std::get<0>(*this));
        }

	const T & operator* () const { return std::get<0>(*this); }
	T & operator* () { return std::get<0>(*this); }
	bool  operator~ () const { return std::get<1>(*this); }
};


template<typename T, char prefix>
std::istream & operator >> (std::istream & is,prefix_expression<T,prefix> & x)
{
        std::string e; is >> e; if (!x.get(e)) is.setstate(std::ios_base::failbit);
        return is;
}



//! match function
//! it matches a pattern against a string
//! @param pattern contains the pattern, the output pattern %1 (%2,%3,...)
//! @param m contains the string
//! @param p1 output pointer with T type that takes the value form %1
//! @return true if match was succesfull
//! TODO if it does not match it should not change the parameters
//! TODO temmplate specialization for string->faster
//! TODO c++0x standard variadic template...



inline void trim(std::string & s,const char* chars = "\n\t\v\f\r ")
{
    s.erase(s.find_last_not_of(chars)+1);
    s.erase(0, s.find_first_not_of(chars));
}

        
inline void tokenize(const std::string& str,std::vector<std::string>& tokens,const std::string& delimiters = " ")
{
    // Skip delimiters at beginning.
    std::string::size_type lastPos = str.find_first_not_of(delimiters, 0);
    // Find first "non-delimiter".
    std::string::size_type pos = str.find_first_of(delimiters, lastPos);
    while (std::string::npos != pos || std::string::npos != lastPos)
    {
        // Found a token, add it to the vector.
        tokens.push_back(str.substr(lastPos, pos - lastPos));
        // Skip delimiters.  Note the "not_of"
        lastPos = str.find_first_not_of(delimiters, pos);
        // Find next "non-delimiter"
        pos = str.find_first_of(delimiters, lastPos);
    }
}
                                                                                    
inline bool match_tokens(const std::vector<std::string> & p_tokens,const std::vector<std::string> & m_tokens,size_t from)
{
        size_t i;
        for(i = from; i < p_tokens.size(); i++)
        if(p_tokens[i] == "%" ) return false; 
        else if(p_tokens[i] == "+%" ) return false; 
        else if (p_tokens[i] != m_tokens[i] ) return false;
        return true;
}

template<typename Arg>
bool match_tokens(const std::vector<std::string> & p_tokens,const std::vector<std::string> & m_tokens,size_t from,std::vector<Arg>* arg)
{
        size_t i;
        for(i = from; i < p_tokens.size(); i++)
        if(p_tokens[i] == "%" ) throw std::runtime_error("match: unhandled type"); 
        else if(p_tokens[i] == "+%") 
        {
                arg->clear();
                for(size_t j = i; j < m_tokens.size(); j++) 
                {
                    Arg arg_item;
                    if(!to(m_tokens[j],arg_item)) return false;
                    arg->push_back(arg_item);
                }
                return true;
        }
        else if (p_tokens[i] != m_tokens[i] ) return false;
        return true;
}


template <typename Arg,typename... Args>
bool match_tokens(const std::vector<std::string> & p_tokens,const std::vector<std::string> & m_tokens,size_t from,Arg arg, Args... args)
{
        size_t i;
        for(i = from; i < p_tokens.size(); i++)
        if(p_tokens[i] == "%") 
        {
                if (to(m_tokens[i],*arg)) return match_tokens(p_tokens,m_tokens,i+1,args...);
                else return false;
        }
        else if (p_tokens[i] != m_tokens[i] ) return false;
        return true;
}


template <typename... Args>
bool match(const std::string & pattern,const std::string & m,Args & ... args)
{
        if(m.size()==0) return false;
        std::vector<std::string> p_tokens;
        std::vector<std::string> m_tokens;
        tokenize(pattern,p_tokens);
        tokenize(m,m_tokens);        

// >>>> 2010 dec 8
        if(m_tokens.size() < p_tokens.size() ) return false;
// <<<<

        return match_tokens(p_tokens,m_tokens,0,&args...);
}




}

namespace io
{

//! load each line from a file ignoring commented parts
//! @param ifn input file name
//! @param comment comment string literal, everyting after comment will be ignored
//! @param lines output string vector that contains each line in the file
inline void load(std::string ifn,std::string comment,std::vector<std::string> & lines) 
{ 
	std::ifstream ifs(ifn.c_str());
	std::string line;
	lines.clear();
	while(std::getline(ifs,line))
	{
		line = line.substr(0,line.find(comment));
		line.erase(line.find_last_not_of("\n\t\v\f\r ")+1);
		line.erase(0, line.find_first_not_of("\n\t\v\f\r "));
		lines.push_back(line);
	}
	ifs.close();
} 

inline void load(std::string ifn,std::string comment,std::vector<std::vector<std::string>> & lines) 
{ 
	std::ifstream ifs(ifn.c_str());
	std::string line;
	lines.clear();
	while(std::getline(ifs,line))
	{
		line = line.substr(0,line.find(comment));
		line.erase(line.find_last_not_of("\n\t\v\f\r ")+1);
		line.erase(0, line.find_first_not_of("\n\t\v\f\r "));
		std::vector<std::string> token;
		util::tokenize(line,token);
		lines.push_back(token);
	}
	ifs.close();
} 


//! load each line from a file ignoring commented parts
//! @param ifn input file name
//! @param comment comment string literal, everyting after comment will be ignored
//! @param lines output string vector that contains each line in the file
template<typename T1,typename T2>
inline void load(std::string ifn,std::string comment,std::vector<std::tuple<T1,T2>> & lines) 
{ 
	std::ifstream ifs(ifn.c_str());
	std::string line;
	lines.clear();
	while(std::getline(ifs,line))
	{
		line = line.substr(0,line.find(comment));
                T1 item1;
                T2 item2;
                std::istringstream iss(line);
                if(!(iss >> item1)) continue;
                if(!(iss >> item2)) continue;
		lines.push_back(std::tuple<T1,T2>(item1,item2));
	}
	ifs.close();
} 


//! load each line from a file ignoring commented parts
//! @param is input stream
//! @param comment comment string literal, everyting after comment will be ignored
//! @param lines output string vector that contains each line in the file 
inline void load(std::istream & is,std::string comment,std::vector<std::string> & lines) 
{ 
	std::string line;
	lines.clear();
	while(std::getline(is,line))
	{
		line = line.substr(0,line.find(comment));
		line.erase(line.find_last_not_of("\n\t\v\f\r ")+1);
		line.erase(0, line.find_first_not_of("\n\t\v\f\r "));
		lines.push_back(line);
	}
}

//! extract lines between two block markers
//! @param block_begin a string that marks the begining of the block
//! @param block_end marks the end of the block
//! @param lines input lines that may contains the marked block
//! @param blocklines output lines between the block markers
inline bool parse_block(const std::string & block_begin,const std::string & block_end, 
                 const std::vector<std::string> & lines,std::vector<std::string> & blocklines)
{
	blocklines.clear();
	size_t i = 0;
	while(i < lines.size())
	if(lines[i].size() > 0)
	{
		if(lines[i] == block_begin)
		{
			i++;
			while(i < lines.size())
			if(lines[i].size() > 0)
			{
				if(lines[i] == block_end)
				break;
				blocklines.push_back(lines[i]);
				i++;
			}
			else i++;
			if(lines[i].empty()) return false;
			else if(lines[i] != block_end) return false;
		}
	i++;
	}
	else i++;
	return true;
}


inline bool parse_block(const std::string & block_begin,const std::string & block_end, 
                 const std::vector<std::string> & lines,std::vector<std::vector<std::string> > & blocklines_array)
{
        std::vector<std::string> blocklines;
	blocklines_array.clear();
	size_t i = 0;
	while(i < lines.size())
	if(lines[i].size() > 0)
	{
		if(lines[i] == block_begin)
		{
			i++;
			while(i < lines.size())
			if(lines[i].size() > 0)
			{
				if(lines[i] == block_end)
                                {
				    blocklines_array.push_back(blocklines);
                                    blocklines.clear();
                                    break;
                                }
				blocklines.push_back(lines[i]);
				i++;
			}
			else i++;
			if(lines[i].empty()) return false;
			else if(lines[i] != block_end) return false;
		}
	i++;
	}
	else i++;
	return true;
}


}

namespace cmd
{
//!
//!  command line argument class
//!  this contains the argc and argv, and the help message.
//!
class arguments
{
private:
	std::list<std::string> arglist;
	std::list<std::vector<std::string> > help;
public:
	//! constructor
	//! @param argc argc from main
	//! @param argv argv from main
	arguments(int argc,char** argv)
	{
		for(int i = 1; i < argc; i++)
			arglist.push_back(argv[i]);
		arglist.push_back("--");
	}
	template<typename T>
	friend class posarg;
	template<typename T>
	friend class vararg;
	template<typename T1,typename T2>
	friend class varargxx;
	template<typename T1,typename T2,typename T3>
	friend class varargxxx;
	template<typename T1,typename T2,typename T3,typename T4>
	friend class varargxxxx;
	template<bool def>
	friend class switcharg;
	template<typename T>
	friend class multivararg;
	
	//! print input
	void print()
	{
		for(std::list<std::string>::iterator it = arglist.begin(); it != arglist.end(); it++)
		std::cout << *it << std::endl;
		std::cout << std::endl;
	    
	}
	//! print help messgae
	//! @param os stream
	//! @param name program name
	void print_help(std::ostream & os,const std::string & name)
	{
		int n = 0;
		os << "Usage: " << name << ' ';
		for(std::list<std::vector<std::string> > :: iterator it = help.begin(); it != help.end(); it++)
		if(it->size() == 1) os << "<arg-" << ++n << ">" << ' ';
		os << " -[option] <option-arg>" << std::endl;
		n = 0;
		for(std::list<std::vector<std::string> > :: iterator it = help.begin(); it != help.end(); it++)
		if(it->size() == 1)
		{
			std::ostringstream oss;
			oss << "<arg-" << ++n << ">";
			os << "   " << std::left << std::setw(15) << oss.str() << ' ' << std::left << std::setw(50) << (*it)[0] << std::endl;
		}
		for(std::list<std::vector<std::string> > :: iterator it = help.begin(); it != help.end(); it++)
		if(it->size() == 3)
		{
			os << "   " << std::left << std::setw(5) << (*it)[0] << ' ';
			os << std::left << std::setw(20) << (*it)[1] << ' ';
			os << std::left << std::setw(50) << (*it)[2] << std::endl;
		}
		   
	}
};

//! positioned cmd line arguments
template<typename T>
class posarg
{
private:
	T var;
	bool found;
public:
	//! constructor
	//! @param args arguments type that contains the command line input
	//! @param help simple help message for this input
	//! @param def default value of this input
	template<typename Tdef>
        posarg(arguments & args,const char* help,const Tdef & def) : var(def)
	{
		std::vector<std::string> help_message;
		help_message.push_back(help);
		args.help.push_back(help_message);
		found = false;
		for(std::list<std::string>::iterator it = args.arglist.begin(); it != args.arglist.end(); it++)
		if(*it != "--") 
		{
			std::istringstream is(*it);
			if ( !(is >> var) )
				throw std::runtime_error("Wrong command line arguments. Try --help!");
			args.arglist.erase(it);
			found = true;
			break;
		} else break;
	}
	//! * operator returns with the parsed value
	//! @return parsed value
	const T & operator * () const { return var; }
	//! ~ operator returns if this input was found in the cmd line.
	//! @return true if it was found
	bool operator ~ () const { return found; }
};

//! optional switch cmd line argument class
//! tempate def contains the default value true/false, if the switch was found
//! it negates
template<bool def>
class switcharg
{
private:
	bool var;
	bool found;
public:
	//! constructor
	//! @param args arguments type that contains the command line input
	//! @param s short version of the switch
	//! @param l long version of the switch
	//! @param help simple help message for this input
	switcharg(arguments & args,const char* s,const char* l,const char* help) : var(def)
	{
		std::vector<std::string> help_message;
		help_message.push_back(s);
		help_message.push_back(l);
		help_message.push_back(help);
		args.help.push_back(help_message);
		found = false;
		for(std::list<std::string>::iterator it = args.arglist.begin(); it != args.arglist.end(); it++)
		if(*it != "--") {
		if( (*it == s) || (*it == l) )
		{
			args.arglist.erase(it);
			var = !var;
			found = true;
			break;
		}} else break;
	}
	//! * operator returns with the switch value
	//! @return switched value
	const bool & operator * () const { return var; }
	//! ~ operator returns if the switch was found in the cmd line.
	//! @return true if it was found
	bool operator ~ () const { return found; }
};

//!
//! simple optional variable input argument class
template<typename T>
class vararg
{
private:
	T var;
	bool found;
public:
	//! constructor
	//! @param args arguments type that contains the command line input
	//! @param s short version of the switch
	//! @param l long version of the switch
	//! @param help simple help message for this input
	//! @param def defualt value of this input
        template<typename Tdef>
	vararg(arguments & args,const char* s,const char* l,const char* help,const Tdef & def) : var(def)
	{
		std::vector<std::string> help_message;
		help_message.push_back(s);
		help_message.push_back(l);
		help_message.push_back(help);
		args.help.push_back(help_message);
		found = false;
		for(std::list<std::string>::iterator it = args.arglist.begin(); it != args.arglist.end(); it++)
		if(*it != "--") {
		if( (*it == s) || (*it == l) )
		{
			if( *++it == "--")
				throw std::runtime_error("Wrong command line arguments. Try --help!");
			std::istringstream is(*it);
			if ( !(is >> var) )
				throw std::runtime_error("Wrong command line arguments. Try --help!");
			it = args.arglist.erase(it);
			args.arglist.erase(--it);
			found = true;
			break;
		}} else break;
	}
	//! * operator returns with the parsed value
	//! @return parsed value
	const T & operator * () const { return var; }
	//! ~ operator returns if the input was found in the cmd line.
	//! @return true if it was found
	bool operator ~ () const { return found; }
};


//!
//! simple optional variable input argument class
template<typename T1,typename T2>
class varargxx
{
public:
//private:
	T1 var1;
        T2 var2;
	bool found;
public:
	//! constructor
	//! @param args arguments type that contains the command line input
	//! @param s short version of the switch
	//! @param l long version of the switch
	//! @param help simple help message for this input
	//! @param def defualt value of this input
        template<typename Tdef1,typename Tdef2>
	varargxx(arguments & args,const char* s,const char* l,const char* help,const Tdef1 & def1,const Tdef2 & def2) : var1(def1), var2(def2)
	{
		std::vector<std::string> help_message;
		help_message.push_back(s);
		help_message.push_back(l);
		help_message.push_back(help);
		args.help.push_back(help_message);
		found = false;
		for(std::list<std::string>::iterator it = args.arglist.begin(); it != args.arglist.end(); it++)
		if(*it != "--") {
		if( (*it == s) || (*it == l) )
		{
			if( *++it == "--")
				throw std::runtime_error("Wrong command line arguments. Try --help!");
			std::istringstream is1(*it);
			if ( !(is1 >> var1) )
				throw std::runtime_error("Wrong command line arguments. Try --help!");
			it = args.arglist.erase(it);
                        
			std::istringstream is2(*it);
			if ( !(is2 >> var2) )
				throw std::runtime_error("Wrong command line arguments. Try --help!");
			it = args.arglist.erase(it);

			args.arglist.erase(--it);
			found = true;
			break;
		}} else break;
	}
	//! * operator returns with the parsed value
	//! @return parsed value
//	const std::tuple<T1,T2> operator * () const { return std::tie(var1,var2); }
	//! ~ operator returns if the input was found in the cmd line.
	//! @return true if it was found
	bool operator ~ () const { return found; }
};

//!
//! simple optional variable input argument class
template<typename T1,typename T2,typename T3>
class varargxxx
{
public:
//private:
	T1 var1;
        T2 var2;
        T3 var3;
	bool found;
public:
	//! constructor
	//! @param args arguments type that contains the command line input
	//! @param s short version of the switch
	//! @param l long version of the switch
	//! @param help simple help message for this input
	//! @param def defualt value of this input
        template<typename Tdef1,typename Tdef2,typename Tdef3>
	varargxxx(arguments & args,const char* s,const char* l,const char* help,const Tdef1 & def1,const Tdef2 & def2,const Tdef3 & def3) : var1(def1), var2(def2), var3(def3)
	{
		std::vector<std::string> help_message;
		help_message.push_back(s);
		help_message.push_back(l);
		help_message.push_back(help);
		args.help.push_back(help_message);
		found = false;
		for(std::list<std::string>::iterator it = args.arglist.begin(); it != args.arglist.end(); it++)
		if(*it != "--") {
		if( (*it == s) || (*it == l) )
		{
			if( *++it == "--")
				throw std::runtime_error("Wrong command line arguments. Try --help!");
			std::istringstream is1(*it);
			if ( !(is1 >> var1) )
				throw std::runtime_error("Wrong command line arguments. Try --help!");
			it = args.arglist.erase(it);
                        
			std::istringstream is2(*it);
			if ( !(is2 >> var2) )
				throw std::runtime_error("Wrong command line arguments. Try --help!");
			it = args.arglist.erase(it);

			std::istringstream is3(*it);
			if ( !(is3 >> var3) )
				throw std::runtime_error("Wrong command line arguments. Try --help!");
			it = args.arglist.erase(it);

			args.arglist.erase(--it);
			found = true;
			break;
		}} else break;
	}
	//! * operator returns with the parsed value
	//! @return parsed value
	const std::tuple<T1,T2,T3> operator * () const { return std::tie(var1,var2,var3); }
	//! ~ operator returns if the input was found in the cmd line.
	//! @return true if it was found
	bool operator ~ () const { return found; }
};

//!
//! simple optional variable input argument class
template<typename T1,typename T2,typename T3,typename T4>
class varargxxxx
{
public:
	T1 var1;
        T2 var2;
        T3 var3;
        T4 var4;
	bool found;
public:
	//! constructor
	//! @param args arguments type that contains the command line input
	//! @param s short version of the switch
	//! @param l long version of the switch
	//! @param help simple help message for this input
	//! @param def defualt value of this input
        template<typename Tdef1,typename Tdef2,typename Tdef3,typename Tdef4>
	varargxxxx(arguments & args,const char* s,const char* l,const char* help,const Tdef1 & def1,const Tdef2 & def2,const Tdef3 & def3,const Tdef4 & def4) : var1(def1), var2(def2), var3(def3), var4(def4)
	{
		std::vector<std::string> help_message;
		help_message.push_back(s);
		help_message.push_back(l);
		help_message.push_back(help);
		args.help.push_back(help_message);
		found = false;
		for(std::list<std::string>::iterator it = args.arglist.begin(); it != args.arglist.end(); it++)
		if(*it != "--") {
		if( (*it == s) || (*it == l) )
		{
			if( *++it == "--")
				throw std::runtime_error("Wrong command line arguments. Try --help!");
			std::istringstream is1(*it);
			if ( !(is1 >> var1) )
				throw std::runtime_error("Wrong command line arguments. Try --help!");
			it = args.arglist.erase(it);
                        
			std::istringstream is2(*it);
			if ( !(is2 >> var2) )
				throw std::runtime_error("Wrong command line arguments. Try --help!");
			it = args.arglist.erase(it);

			std::istringstream is3(*it);
			if ( !(is3 >> var3) )
				throw std::runtime_error("Wrong command line arguments. Try --help!");
			it = args.arglist.erase(it);

			std::istringstream is4(*it);
			if ( !(is4 >> var4) )
				throw std::runtime_error("Wrong command line arguments. Try --help!");
			it = args.arglist.erase(it);

			args.arglist.erase(--it);
			found = true;
			break;
		}} else break;
	}
	//! * operator returns with the parsed value
	//! @return parsed value
	const std::tuple<T1,T2,T3,T4>  operator * () const { return std::tie(var1,var2,var3,var4); }
	//! ~ operator returns if the input was found in the cmd line.
	//! @return true if it was found
	bool operator ~ () const { return found; }
};


//! optional variable input argument that can occur more than once
template<typename T>
class multivararg
{
private:
	typename std::vector<T> var;
	bool found;
public:
	//! constructor
	//! @param args arguments type that contains the command line input
	//! @param s short version of the switch
	//! @param l long version of the switch
	//! @param help simple help message for this input
	//! @param def defualt value of this input
	multivararg(arguments & args,const char* s,const char* l,const char* help)
	{
		std::vector<std::string> help_message;
		help_message.push_back(s);
		help_message.push_back(l);
		help_message.push_back(help);
		args.help.push_back(help_message);
		found = false;
		for(std::list<std::string>::iterator it = args.arglist.begin(); it != args.arglist.end(); it++)
		if(*it != "--") {
		if( (*it == s) || (*it == l) )
		{
			if( *++it == "--")
				throw std::runtime_error("Wrong command line arguments. Try --help!");
			std::istringstream is(*it);
			T v;
			if ( !(is >> v) )
				throw std::runtime_error("Wrong command line arguments. Try --help!");
			var.push_back(v);
			it = args.arglist.erase(it);
			it = args.arglist.erase(--it);
			it--;
			found = true;
		}} else break;
	}
	//! * operator returns with the parsed value vector
	//! @return parsed value vector
	const std::vector<T> & operator * () const { return var; }
	//! ~ operator returns if the input was found at least once in the cmd line.
	//! @return true if it was found
	bool operator ~ () const { return found; }
};

}




#endif // CMDIOUTIL_H

